package pts

import (
	"strings"
)

// ArrConcat 将多个数组的元素拼接到一个数组
func ArrConcat[V any](arr []V, arrs ...[]V) []V {
	for _, a := range arrs {
		arr = append(arr, a...)
	}
	return arr
}

// ArrUnion 将多个数的值返回唯一的并集数组
func ArrUnion[V comparable](arr []V, arrs ...[]V) []V {
	for _, a := range arrs {
		arr = append(arr, a...)
	}
	return ArrUniq(arr)
}

// ArrChunk 将一个数组分割成大小的组。如果数组不能被平均分配，那么最后一块将是剩下的元素
func ArrChunk[V any](arr []V, sizes ...int) [][]V {
	var (
		size int
		arr2 [][]V
	)

	if len(sizes) > 0 {
		size = sizes[0]
	}

	for i, l, s := 0, len(arr), Max(1, size); i < l; i += s {
		arr2 = append(arr2, arr[i:Min(l, i+s)])
	}

	return arr2
}

// ArrIndexOf 查找指定元素在数组中的位置下标，某不存在则返回-1
func ArrIndexOf[V comparable, T []V](arr T, val V) int {
	for i, v := range arr {
		if v == val {
			return i
		}
	}
	return -1
}

// ArrIncludes 判断数组是否包含指定元素
func ArrIncludes[V comparable, T []V](arr T, val V) bool {
	for _, a := range arr {
		if a == val {
			return true
		}
	}
	return false
}

// ArrFill 元素填充：将数组内元素全部填充为指定值
func ArrFill[V any, T []V](arr *T, val V) *T {
	for i := range *arr {
		(*arr)[i] = val
	}
	return arr
}

// ArrFilter 元素筛选，fn()返回true的元素保留
func ArrFilter[V any, T []V](arr T, fn func(val V, idx int) bool) T {
	var arr2 T
	for i, a := range arr {
		if fn(a, i) {
			arr2 = append(arr2, a)
		}
	}
	return arr2
}

// ArrMap 元素重构：使用fn()的返回值替换原值
func ArrMap[V any, R any](arr []V, fn func(val V, idx int) R) []R {
	var arr2 []R
	for i, a := range arr {
		arr2 = append(arr2, fn(a, i))
	}
	return arr2
}

// ArrReduce 接收一个函数作为累加器，数组中的每个值（从左到右）开始合并，最终为一个值
func ArrReduce[V any, R any](arr []V, fn func(prev R, curr V, idx int, arr []V) R, initVal ...R) R {
	var res R

	if len(initVal) > 0 {
		res = initVal[0]
	}

	for i, v := range arr {
		res = fn(res, v, i, arr)
	}

	return res
}

// ArrUniq 数组去重
func ArrUniq[V comparable](arr []V) []V {
	var (
		arr2  []V
		cache = make(map[V]bool)
	)

	for _, v := range arr {
		if !cache[v] {
			cache[v] = true
			arr2 = append(arr2, v)
		}
	}

	return arr2
}

// ArrSample 从数组中随机返回n个元素，n强制取值范围[1,len(arr)]
func ArrSample[V any](arr []V, count ...int) []V {
	var (
		n    int
		arr2 []V
	)

	if len(count) > 0 {
		n = count[0]
	}

	for n = Max(1, n); n > 0; n-- {
		if l := len(arr); l > 0 {
			i := RandInt(1, l)
			arr2 = append(arr2, arr[i-1])
			arr = append(arr[:i-1], arr[i:]...)
		}
	}

	return arr2
}

// ArrSampleOne 从数组中随机返回1个元素
func ArrSampleOne[V any](arr []V) V {
	var v V

	if l := len(arr); l > 0 {
		v = arr[RandInt(0, l-1)]
	}

	return v
}

// ArrShuffle 将一个数组随机打乱，返回一个新的数组
func ArrShuffle[V any](arr []V) []V {
	return ArrSample(arr, len(arr))
}

// ArrCount 返回数组指定元素的个数
func ArrCount[V comparable](arr []V, vals ...V) int {
	var (
		val   V
		count int
	)

	if len(vals) > 0 {
		val = vals[0]
	}

	for _, v := range arr {
		if v == val {
			count++
		}
	}

	return count
}

// ArrSum 数组所有元素求和
func ArrSum[V Numeric](arr []V) V {
	return ArrReduce(arr, func(prev V, curr V, idx int, arr []V) V {
		return prev + curr
	})
}

// ArrMean 数组所有元素的平均值
func ArrMean[V Numeric](arr []V) float64 {
	var v float64

	if l := len(arr); l > 0 {
		v = float64(ArrSum(arr)) / float64(len(arr))
	}

	return v
}

// ArrProduct 数组所有元素相乘的乘积
func ArrProduct[V Numeric](arr []V) V {
	return ArrReduce(arr, func(prev V, curr V, idx int, arr []V) V {
		return prev * curr
	}, 1)
}

// ArrFind 查找元素：返回fn()首次为true的元素，否则返回
func ArrFind[V any, T []V](arr T, fn func(val V, idx int) bool) V {
	var empty V
	for i, a := range arr {
		if fn(a, i) {
			return a
		}
	}
	return empty
}

// ArrFindIndex 查找元素：返回fn()首次为true的元素所在下标，否则返回-1
func ArrFindIndex[V any, T []V](arr T, fn func(val V, idx int) bool) int {
	for i, a := range arr {
		if fn(a, i) {
			return i
		}
	}
	return -1
}

// ArrFindLast 查找元素：返回fn()最后一次为true的元素，否则返回
func ArrFindLast[V any, T []V](arr T, fn func(val V, idx int) bool) V {
	var empty V
	for i := len(arr) - 1; i >= 0; i-- {
		if fn(arr[i], i) {
			return arr[i]
		}
	}
	return empty
}

// ArrFindLastIndex 查找元素：返回fn()最后一次为true的元素所下在标，否则返回-1
func ArrFindLastIndex[V any, T []V](arr T, fn func(val V, idx int) bool) int {
	for i := len(arr) - 1; i >= 0; i-- {
		if fn(arr[i], i) {
			return i
		}
	}
	return -1
}

// ArrSome 循环数组，并在fn()返回true时提前结束循环
func ArrSome[V any, T []V](arr T, fn func(val V, idx int) bool) bool {
	for i, a := range arr {
		if fn(a, i) {
			return true
		}
	}
	return false
}

// ArrEvery 循环数组，并在fn()返回false时提前结束循环
func ArrEvery[V any, T []V](arr T, fn func(val V, idx int) bool) bool {
	for i, a := range arr {
		if !fn(a, i) {
			return false
		}
	}
	return true
}

// ArrShift 从数组中移除第一个元素，并返回
//
// - 无可移除元素时返回指定类型的空值
func ArrShift[V any, T []V](arr *T) V {
	var v V
	if l := len(*arr); l > 0 {
		v = (*arr)[0]
		*arr = (*arr)[1:]
	}
	return v
}

// ArrUnShift 添加一些元素到数组开头，并返回该数组当前的元素个数
//
// - 无可移除元素时返回指定类型的空值
func ArrUnShift[V any, T []V](arr *T, vals ...V) int {
	*arr = ArrConcat(vals, *arr)
	return len(*arr)
}

// ArrPop 从数组中移除最后一个元素，并返回
//
// - 无可移除元素时返回指定类型的空值
func ArrPop[V any, T []V](arr *T) V {
	var v V
	if l := len(*arr); l > 0 {
		v = (*arr)[l-1]
		*arr = (*arr)[:l-1]
	}
	return v
}

// ArrPush 添加一些元素到数组末尾，并返回该数组当前的元素个数
//
// - 无可移除元素时返回指定类型的空值
func ArrPush[V any, T []V](arr *T, vals ...V) int {
	*arr = ArrConcat(*arr, vals)
	return len(*arr)
}

// ArrSplice 从数组arr的起始位置start开始，删去length个元素，并将val拼接至最后，返回删除的元素切片
//
// - 若start为负数，则从尾部开始算，如：-5，表示从倒数第5个元素开始
//
// - 此方法传入的arr为指针(*T)，会改变原数组
func ArrSplice[V any, T []V](arr *T, start, length int, val ...V) T {
	l := len(*arr)

	start = IIf(start < 0, Max(l+start, 0), Min(start, l))
	end := Min(start+length, l)

	arr2 := make(T, end-start)
	if end > start {
		copy(arr2, (*arr)[start:end])
		*arr = append((*arr)[0:start], append((*arr)[end:], val...)...)
	} else {
		*arr = append(*arr, val...)
	}

	return arr2
}

// ArrJoin 将数组元素转为string，为使用sep拼接
func ArrJoin[V any, T []V, R any](arr T, sep R) string {
	return strings.Join(ArrMap(arr, func(v V, i int) string {
		return Str(v)
	}), Str(sep))
}

// Join 将数组以指定分隔符拼接为字符串
func Join[V any, T []V, R any](arr T, sep R) string {
	return ArrJoin[V, T, R](arr, sep)
}
